﻿
using Xacml.Core;
using Xacml.Core.Interfaces;
using Xacml.Core.Runtime;
using Xacml.Core.Runtime.DataTypes;
using System;
using System.Collections;

namespace Xacml.Core.Runtime.Functions
{
  public abstract class FunctionBase : IFunction, IFunctionParameter
  {
    public bool IsBag
    {
      get
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_function_usage]);
      }
    }

    public int BagSize
    {
      get
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_function_usage]);
      }
    }

    public ArrayList Elements
    {
      get
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_function_usage]);
      }
    }

    public abstract string Id { get; }

    public abstract IDataType Returns { get; }

    public abstract IDataType[] Arguments { get; }

    public virtual bool VarArgs
    {
      get
      {
        return false;
      }
    }

    public IDataType GetType(EvaluationContext context)
    {
      return (IDataType) DataTypeDescriptor.Function;
    }

    public virtual object GetTypedValue(IDataType dataType, int parNo)
    {
      return (object) this;
    }

    public IFunction GetFunction(int parNo)
    {
      return (IFunction) this;
    }

    public abstract EvaluationValue Evaluate(EvaluationContext context, params IFunctionParameter[] args);

    protected int GetIntegerArgument(IFunctionParameter[] args, int index)
    {
      return (int) args[index].GetTypedValue((IDataType) DataTypeDescriptor.Integer, index);
    }

    protected bool GetBooleanArgument(IFunctionParameter[] args, int index)
    {
      return (bool) args[index].GetTypedValue((IDataType) DataTypeDescriptor.Boolean, index);
    }

    protected Uri GetAnyUriArgument(IFunctionParameter[] args, int index)
    {
      return (Uri) args[index].GetTypedValue((IDataType) DataTypeDescriptor.AnyUri, index);
    }

    protected string GetStringArgument(IFunctionParameter[] args, int index)
    {
      return (string) args[index].GetTypedValue((IDataType) DataTypeDescriptor.String, index);
    }

    protected Base64Binary GetBase64BinaryArgument(IFunctionParameter[] args, int index)
    {
      return (Base64Binary) args[index].GetTypedValue((IDataType) DataTypeDescriptor.Base64Binary, index);
    }

    protected System.DateTime GetDateArgument(IFunctionParameter[] args, int index)
    {
      return (System.DateTime) args[index].GetTypedValue((IDataType) DataTypeDescriptor.Date, index);
    }

    protected System.DateTime GetTimeArgument(IFunctionParameter[] args, int index)
    {
      return (System.DateTime) args[index].GetTypedValue((IDataType) DataTypeDescriptor.Time, index);
    }

    protected System.DateTime GetDateTimeArgument(IFunctionParameter[] args, int index)
    {
      return (System.DateTime) args[index].GetTypedValue((IDataType) DataTypeDescriptor.DateTime, index);
    }

    protected DayTimeDuration GetDayTimeDurationArgument(IFunctionParameter[] args, int index)
    {
      return (DayTimeDuration) args[index].GetTypedValue((IDataType) DataTypeDescriptor.DayTimeDuration, index);
    }

    protected double GetDoubleArgument(IFunctionParameter[] args, int index)
    {
      return (double) args[index].GetTypedValue((IDataType) DataTypeDescriptor.Double, index);
    }

    protected HexBinary GetHexBinaryArgument(IFunctionParameter[] args, int index)
    {
      return (HexBinary) args[index].GetTypedValue((IDataType) DataTypeDescriptor.HexBinary, index);
    }

    protected Rfc822Name GetRfc822NameArgument(IFunctionParameter[] args, int index)
    {
      return (Rfc822Name) args[index].GetTypedValue((IDataType) DataTypeDescriptor.Rfc822Name, index);
    }

    protected X500Name GetX500NameArgument(IFunctionParameter[] args, int index)
    {
      return (X500Name) args[index].GetTypedValue((IDataType) DataTypeDescriptor.X500Name, index);
    }

    protected YearMonthDuration GetYearMonthDurationArgument(IFunctionParameter[] args, int index)
    {
      return (YearMonthDuration) args[index].GetTypedValue((IDataType) DataTypeDescriptor.YearMonthDuration, index);
    }
  }
}
